/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import { spawnSync, SpawnSyncOptionsWithBufferEncoding } from 'child_process';
import fs from 'fs';
import path from 'path';

import { HVIGOR_PROJECT_CACHES_HOME, HVIGOR_WRAPPER_PNPM_SCRIPT_PATH, HVIGOR_WRAPPER_TOOLS_HOME } from '../../../../common/const/path-const.js';
import { HvigorCoreNode } from '../../../external/core/hvigor-core-node.js';
import { HvigorTaskGroupType } from '../../../external/task/core-task.js';
import { DefaultTask } from '../../../external/task/default-task.js';
import { HvigorLogger } from '../../../log/hvigor-log.js';
import { JsonReader } from '../../../util/json-reader.js';

const THIRTY_DAYS_MS: number = 30 * 24 * 60 * 60 * 1000;
const LOG = HvigorLogger.getLogger('prune');

/**
 * hvigor prune命令 任务
 *
 * @since 2023/6/20
 */
export class PruneTask extends DefaultTask {
  constructor(hvigorNode: HvigorCoreNode) {
    super(hvigorNode, {
      name: 'prune',
      group: HvigorTaskGroupType.OTHER_TASK_GROUP,
      isEnabled: true,
      description: 'Clean up old hvigor cache files and remove unreferenced packages from store.',
    });
  }

  registryAction(): Function {
    return async () => {
      LOG.info('Clear the cache of the hvigor file');
      const deletePromises = await deleteCacheFiles();
      await Promise.all(deletePromises);
      LOG.info('Remove unreferenced packages from the store');
      execStorePruneCommand();
    };
  }
}

// 删除 超过30天的 缓存文件
async function deleteCacheFiles(): Promise<Promise<void>[]> {
  // 获取project_cache 目录里文件
  if (!fs.existsSync(HVIGOR_PROJECT_CACHES_HOME)) {
    return [];
  }
  const cacheDirs = fs.readdirSync(HVIGOR_PROJECT_CACHES_HOME);

  // 遍历文件 判断是否为 新项目 （新项目包含 metadata.json）
  return cacheDirs.map(async (dirName) => {
    const srcDir = path.resolve(HVIGOR_PROJECT_CACHES_HOME, dirName);

    // 是否为文件夹
    const status: fs.Stats = fs.statSync(srcDir);
    if (status.isDirectory()) {
      // 检查项目是否为新版本 （是否有 metadata.json 文件）
      const metadataPath = path.resolve(srcDir, 'workspace', 'metadata.json');

      // 如果文件存在, 去判断 时间戳是否超过30天 超过30天则 删除这个 cacheDir
      if (fs.existsSync(metadataPath) && fs.statSync(metadataPath).isFile() && needDeleteDir(metadataPath)) {
        LOG.info('Clear the hvigor cache file: ', srcDir);
        await fs.promises.rm(srcDir, { force: true, recursive: true });
      }
    }
  });
}

// 执行 pnpm store prune 命令
function execStorePruneCommand(): void {
  const options: SpawnSyncOptionsWithBufferEncoding = {
    cwd: HVIGOR_WRAPPER_TOOLS_HOME,
    stdio: ['inherit', 'inherit', 'inherit'],
    windowsHide: true,
  };

  const storePruneCmdParams = ['store', 'prune'];

  const executeResult = spawnSync(HVIGOR_WRAPPER_PNPM_SCRIPT_PATH, storePruneCmdParams, options);
  if (executeResult.status !== 0) {
    LOG.printErrorExit('PNPM_STORE_PRUNE_EXECUTE_FAILED', [executeResult.error?.message]);
  }
}

// 判断 缓存文件是否需要删除 : lastUpdatedTime 时间 超过30天
function needDeleteDir(metadataPath: string): boolean {
  // 获取时间戳
  const metadataJsonFile = JsonReader.getJsonObj(metadataPath);
  const lastUpdatedTimeValue = metadataJsonFile.lastUpdatedTime;
  if (lastUpdatedTimeValue) {
    // 判断 是否超过30天时间
    return new Date(new Date().getTime() - THIRTY_DAYS_MS).getTime() > lastUpdatedTimeValue;
  }
  return false;
}
